/*
    <one line to give the library's name and an idea of what it does.>
    Copyright (C) 2012  Guillaume <email>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/


#include "ms3dStructure.h"

namespace atomism
{

bool ms3dObject::is3dObjectRegisteredInPython=0;
msRegistrar ms3dObject::Registrar("ms3dObject", ms3dObject::createInstance);

void ms3dObject::registryInPython()
{
  #if USE_PYTHON
  msTreeMapper::registryInPython();
  
  if( ! ms3dObject::is3dObjectRegisteredInPython ) {
    
     using namespace boost::python;
     
     class_<ms3dObject,bases<msTreeMapper>,boost::shared_ptr<ms3dObject> >
          ("ms3dObject","Base class for 3D object",no_init)
     .def( "setColor" ,  (void(ms3dObject::*)( double, double, double ) ) &ms3dObject::setColor,
	  "Set the color of the object (r,g,b in [0,1])")
     .def( "show" ,   &ms3dObject::show, "Display the object" );
     
    ms3dObject::is3dObjectRegisteredInPython=1;
   }
#endif
 }

void ms3dObject::set(vtkPolyDataAlgorithm* obj, msColor c) {
 
 LOGGER_ENTER_FUNCTION_DBG("void ms3dObject::set(vtkPolyDataAlgorithm* obj, msColor c)",getFullId());
 Color = c; Object = obj;
 Mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
 Mapper->SetInputConnection( Object->GetOutputPort() );
 Actor=  vtkSmartPointer<vtkActor>::New();
 Actor->SetMapper( Mapper );
 Actor->GetProperty()->SetColor(Color.red,Color.green,Color.blue);
 LOGGER_EXIT_FUNCTION();
 }
	      
void ms3dObject::setColor(double r,double v,double b)
{ Color.red=r;Color.green=v, Color.blue=b; 
 }
 

void ms3dObject::setColor(std::string rgb)
{ 
 std::vector<int> ints;
 fillVecFromString<int>(rgb,ints," ");
 Color.red=double(ints[0])/255.;
 Color.green=double(ints[1])/255.;
 Color.blue=double(ints[2])/255.; 
 }

void ms3dObject::show()
{
 vtkSmartPointer<vtkRenderer> Renderer = vtkSmartPointer<vtkRenderer>::New();
 Renderer->SetBackground(25/255.,50/255.,100./255.);
 Actor->GetProperty()->SetColor(Color.red,Color.green,Color.blue);
 Renderer->AddActor(Actor);
 
 vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New();;
 renWin->AddRenderer( Renderer );
 renWin->SetSize( 400, 400 );

 vtkSmartPointer<vtkRenderWindowInteractor> iren = 
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
 iren->SetRenderWindow(renWin);

 renWin->Render();
 vtkSmartPointer<vtkInteractorStyleTrackballCamera> style =
         vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
	 
 iren->SetInteractorStyle(style);
 iren->Initialize();
 iren->Start();
 }
 
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

bool ms3dSphere::is3dSphereRegisteredInPython=0;
msRegistrar ms3dSphere::Registrar("ms3dSphere", ms3dSphere::createInstance);
 
void ms3dSphere::registryInPython() {
  
#if USE_PYTHON
  msRegister::registryInPython();
  if( !ms3dSphere::is3dSphereRegisteredInPython ) {
    
    using namespace boost::python;
    
    class_<ms3dSphere,bases<ms3dObject>,boost::shared_ptr<ms3dSphere> >
        ("ms3dSphere", "A sphere object ", no_init)
        .def( "New", &ms3dSphere::New , "Return a shared pointer to a new object" )
	.staticmethod("New")
	.def( "setGeometry" ,   (void(ms3dSphere::*)(double,double,double,double))&ms3dSphere::setGeometry,
	  "Set the geometry: double x, y, z of the center followed by radius ")
	.def( "setGeometry" ,   (void(ms3dSphere::*)(const Eigen::Vector3d&,double))&ms3dSphere::setGeometry,
	      "Set the geometry: Eigen::Vector3d of the center followed by radius ")
	.def( "setResolution" ,   &ms3dSphere::setResolution,
	  "Set the resolution: number of longitude/latitude ");
         ms3dSphere::is3dSphereRegisteredInPython=1;
         }
#endif  
}

void ms3dSphere::setGeometry(double x, double y, double z, double r)
{
 Sphere->SetCenter(X=x,Y=y,Z=z);
 Sphere->SetRadius(Rayon=r);
 }
 
void ms3dSphere::setGeometry(const Eigen::Vector3d& center,double r)
{
 Sphere->SetCenter(X=center[0],Y=center[1],Z=center[2]);
 Sphere->SetRadius(Rayon=r);
}

void ms3dSphere::setPosition(const Eigen::Vector3d& center)
{
 Sphere->SetCenter(X=center[0],Y=center[1],Z=center[2]);
 }
 
void ms3dSphere::setRadius(double r)
{
 Sphere->SetRadius(Rayon=r);
 }
 
void ms3dSphere::setResolution(int resol)
{
 Sphere->SetThetaResolution(Resolution=resol);
 Sphere->SetPhiResolution(Resolution);
 }
 
//-------------------------------------------------------------------------------
//------------------------------------------------------------------------------- 
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

bool ms3dTube::is3dTubeRegisteredInPython=0;
msRegistrar ms3dTube::Registrar("ms3dTube", ms3dTube::createInstance);
 
void ms3dTube::registryInPython(){
  
#if USE_PYTHON
  msRegister::registryInPython();
  if( !ms3dTube::is3dTubeRegisteredInPython ) {
    
    using namespace boost::python;
    class_<ms3dTube,bases<ms3dObject>,boost::shared_ptr<ms3dTube> >
        ("ms3dTube", "A tube object ", no_init )
        .def( "New", &ms3dTube::New , "Return a shared pointer to a new object" )
	.staticmethod("New")
	.def( "setGeometry" , &ms3dTube::setGeometry,
	      "Set the geometry; arg1 & arg2: Eigen::Vector3d of the extremities; arg3: radius ")
	.def( "setExtremities" ,   &ms3dTube::setExtremities,
	      "Set the extremities: arg1 & arg2: Eigen::Vector3d of the extremities ")
	.def( "setRadius" ,   &ms3dTube::setRadius,
	      "Set the radius: arg1 : radius (double) ")
	.def( "setResolution" ,   &ms3dTube::setResolution,
	      "Set the resolution: number of faces ");
	
    ms3dTube::is3dTubeRegisteredInPython=1;
   }
#endif
 }
 
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------


void ms3dTube::updateTube() {
  
 LineSource=vtkSmartPointer<vtkLineSource>::New();
 LineSource->SetPoint1(pt1[0],pt1[1],pt1[2]);
 LineSource->SetPoint2(pt2[0],pt2[1],pt2[2]);
 Tube=vtkSmartPointer<vtkTubeFilter>::New();
 Tube->SetGlobalWarningDisplay(0);
 Tube->SetInputConnection(LineSource->GetOutputPort());
 Tube->SetRadius(Rayon); 
 Tube->SetNumberOfSides(Resolution);
 Tube->Update();
 set(Tube,msColor(0.5,0.7,0.9));
 }

//-------------------------------------------------------------------------------
//------------------------------------------------------------------------------- 

void ms3dTube::setGeometry(const Eigen::Vector3d& p1,const Eigen::Vector3d& p2,double r)
{
 pt1=p1; pt2=p2; Rayon=r;
 LineSource->SetPoint1(pt1[0],pt1[1],pt1[2]);
 LineSource->SetPoint2(pt2[0],pt2[1],pt2[2]); 
 Tube->SetRadius(Rayon); 
 }

void ms3dTube::setResolution(int resol)
{
 Tube->SetNumberOfSides(resol);
 }

void ms3dTube::setExtremities(const Eigen::Vector3d& p1,const Eigen::Vector3d& p2)
{
 pt1=p1; pt2=p2; 
 LineSource->SetPoint1(pt1[0],pt1[1],pt1[2]);
 LineSource->SetPoint2(pt2[0],pt2[1],pt2[2]); 
 }
 
void ms3dTube::setRadius(double r)
{
 Tube->SetRadius(Rayon=r); 
 }
 
//-------------------------------------------------------------------------------
//------------------------------------------------------------------------------- 
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------


bool ms3dStructure::is3dStructureRegisteredInPython=0;
msRegistrar ms3dStructure::Registrar("ms3dStructure", ms3dStructure::createInstance);

void ms3dStructure::registryInPython() {
  
#if USE_PYTHON
  msRegister::registryInPython();
  if( !ms3dStructure::is3dStructureRegisteredInPython ) {
    
    using namespace boost::python;
    
    class_<ms3dStructure,bases<msRegister>,boost::shared_ptr<ms3dStructure> >
        ("ms3dStructure","A container of ms3dObject objects", no_init )
        .def( "New", &ms3dStructure::New , 
	      "Return a shared pointer to a new object") 
	.staticmethod("New")
	.def( "addObject" ,   &ms3dStructure::add ,
	      "Add an shared_ptr<ms3dObject> to the container" )
	.def( "show" ,   (void(ms3dStructure::*)())&ms3dStructure::show ,
	      "Display the 3D structure")
        .def( "clear" ,   &ms3dStructure::clear,
	      "Clear the container" )  
	.def("savePicture", &ms3dStructure::savePicture,
	     "Save the picture. arg1: filename")
    ;
    ms3dStructure::is3dStructureRegisteredInPython=1;
   }
#endif
 }
 
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

void ms3dStructure::resize(size_t n)
{
 resizeChildren<ms3dObject>(Objects,n);
 }

//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

void ms3dStructure::clear()
{
 resizeChildren<ms3dObject>(Objects,0);
 }

//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

void ms3dStructure::show()
{
 vtkSmartPointer<vtkRenderer> Renderer = vtkSmartPointer<vtkRenderer>::New();
 Renderer->SetBackground(25/255.,50/255.,100./255.);
 
 msChildren<ms3dObject>::iterator it=Objects.begin();
 //std::vector<boost::shared_ptr<ms3dObject> >::iterator it=Objects.begin();
 
 for( ;it != Objects.end(); it++ )
 {(*it)->Actor->GetProperty()->SetColor((*it)->Color.red,(*it)->Color.green,(*it)->Color.blue);
 
  Renderer->AddActor((*it)->Actor);}
  
 
 vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New();;
 renWin->AddRenderer( Renderer );
 renWin->SetSize( 400, 400 );

 vtkSmartPointer<vtkRenderWindowInteractor> iren = 
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
 iren->SetRenderWindow(renWin);

 renWin->Render();
 vtkSmartPointer<vtkInteractorStyleTrackballCamera> style =
         vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
	 
 iren->SetInteractorStyle(style);
 iren->Initialize();
 iren->Start();
 }

//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

void ms3dStructure::show(vtkRenderer* Renderer)
{
 msChildren<ms3dObject>::iterator it=Objects.begin();
 
 for( ;it != Objects.end(); it++ )
    {
    (*it)->Actor->GetProperty()->SetColor((*it)->Color.red,(*it)->Color.green,(*it)->Color.blue);
    Renderer->AddActor((*it)->Actor);
    }
 }

//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

void ms3dStructure::add(boost::shared_ptr<ms3dObject> obj)
{
 addElementToChildren<ms3dObject>(Objects,obj);
 }
 
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

void ms3dStructure::savePicture(std::string file)
{ /*
 vtkSmartPointer<vtkRenderer> Renderer = vtkSmartPointer<vtkRenderer>::New();
 Renderer->SetBackground(25/255.,50/255.,100./255.);
 
 msChildren<ms3dObject>::iterator it=Objects.begin();
 
 for( ;it != Objects.end(); it++ )
 {(*it)->Actor->GetProperty()->SetColor((*it)->Color.red,(*it)->Color.green,(*it)->Color.blue);
  Renderer->AddActor((*it)->Actor);
  } 
  
 vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New();;
 renWin->AddRenderer( Renderer );
 renWin->SetSize( 400, 400 );

 vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
 iren->SetRenderWindow(renWin);
   
 vtkWindowToImageFilter *filter = vtkWindowToImageFilter::New();
 filter->SetInput(renWin);
 vtkJPEGWriter *jw = vtkJPEGWriter::New();
 jw->SetInput(filter->GetOutput());
 jw->SetFileName(file.c_str());
 
 renWin->Render();

 jw->Write();
 jw->Delete();
  
 filter->Delete();
 iren->Delete();*/
 }

}
